<template>
  <div :class="wrapClass">
    <div ref="textRef" class="leading-relaxed break-words"></div>
    <div v-if="!inversion">
      <template v-if="!asRawText">
        <div
          v-if="textVal"
          class="markdown-body"
          :class="{ 'markdown-body-generate': loading }"
          v-html="textVal"
        />
      </template>
      <div v-else class="whitespace-pre-wrap" v-text="textVal" />
    </div>
    <div v-else class="whitespace-pre-wrap" v-text="textVal"></div>
  </div>
</template>

<script setup lang="ts">
import { computed } from "vue";
import MarkdownIt from "markdown-it";
import MdKatex from "@vscode/markdown-it-katex";
import "katex/dist/katex.min.css";
import MdLinkAttributes from "markdown-it-link-attributes";
import MdMermaid from "mermaid-it-markdown";
import hljs from "highlight.js";

const props = defineProps<{
  inversion?: boolean;
  error?: boolean;
  text?: string;
  reasoning?: string;
  loading?: boolean;
  asRawText?: boolean;
}>();

const mdi = new MarkdownIt({
  html: false,
  linkify: true,
  highlight(code, language) {
    const validLang = !!(language && hljs.getLanguage(language));
    if (validLang) {
      const lang = language ?? "";
      return highlightBlock(
        hljs.highlight(code, { language: lang }).value,
        lang
      );
    }
    return highlightBlock(hljs.highlightAuto(code).value, "");
  },
});

mdi
  .use(MdLinkAttributes, { attrs: { target: "_blank", rel: "noopener" } })
  .use(MdKatex)
  .use(MdMermaid);
const wrapClass = computed(() => {
  return [
    "text-wrap",
    "min-w-20px",
    "rounded-md",
    "px-3 py-2",
    props.inversion ? "bg-#d2f9d1" : "bg-#f4f6f8",
    props.inversion ? "dark:bg-#414158" : "dark:bg-#1e1e20",
    props.inversion ? "message-request" : "message-reply",
    { "text-red-500": props.error },
  ];
});

const textVal = computed(() => {
  const value = props.text ?? "";
  if (!props.asRawText) {
    const escapedText = escapeBrackets(escapeDollarNumber(value));
    return mdi.render(escapedText);
  }
  return value;
});

function highlightBlock(str: string, lang?: string) {
  return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">复制代码</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`;
}
function escapeBrackets(text: string) {
  const pattern =
    /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g;
  return text.replace(
    pattern,
    (match, codeBlock, squareBracket, roundBracket) => {
      if (codeBlock) return codeBlock;
      else if (squareBracket) return `$$${squareBracket}$$`;
      else if (roundBracket) return `$${roundBracket}$`;
      return match;
    }
  );
}

function escapeDollarNumber(text: string) {
  let escapedText = "";

  for (let i = 0; i < text.length; i += 1) {
    let char = text[i];
    const nextChar = text[i + 1] || " ";

    if (char === "$" && nextChar >= "0" && nextChar <= "9") char = "\\$";

    escapedText += char;
  }

  return escapedText;
}
</script>

<style lang="scss">
@use "./style.scss";
</style>
